#include "../src/polytomousrasch.c"

#include <assert.h>
#include <stdio.h>

typedef struct _PolytomousRaschTestDatum PolytomousRaschTestDatum;
struct _PolytomousRaschTestDatum 
{
  struct
    {
      unsigned int  x;
      double        beta;
      double        tau[5];
    }                           input;

  double                        output;
};

static void
test_polytomous_rasch (void)
{
  PolytomousRaschTestDatum data[] = 
    {{{4, 4.12133, {0.775378, 1.63641, 0.0169398, 3.11458, 1.54293}}, -2.67745}, {{0, 1.08568, {1.73603, 1.12348, 4.258, 2.63745, 2.11124}}, -0.718569}, {{0, 1.39164, {0.226321, 2.40196, 0.890382, 1.98205, 2.1402}}, -2.18329}, {{5, 3.40611, {0.826775, 0.956372, 4.67769, 3.62439, 1.26849}}, -0.607828}, {{3, 1.83504, {3.90231, 1.98799, 1.25155, 3.72047, 2.35938}}, -2.02656}, {{3, 0.902301, {4.51552, 2.59698, 3.10138, 3.26485, 2.40427}}, -7.53899}, {{0, 1.20535, {2.87506, 0.862883, 1.51389, 4.22329, 0.734858}}, -0.514665}, {{4, 2.45677, {0.687118, 3.26692, 1.05717, 3.83238, 4.41863}}, -2.15679}, {{2, 1.43188, {2.15486, 1.8444, 3.16709, 2.71141, 4.79548}}, -1.76652}, {{5, 0.942097, {3.65157, 0.114429, 1.6941, 2.67725, 1.2473}}, -4.94624}};

  for (unsigned int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
    {
#define taufunc(_k) data[i].input.tau[_k]
      double actual = log_polytomous_rasch (data[i].input.x,
                                            data[i].input.beta,
                                            taufunc,
                                            5);
#undef taufunc

      assert (      fabs (actual - data[i].output) 
                 <= 1e-5 * (1 + fabs (actual) + fabs (data[i].output))
              || (fprintf (stderr, "fail: %g != %g\n", actual, data[i].output),
                  0));
    }
}

static void
test_dbeta (void)
{
  PolytomousRaschTestDatum data[] = 
     {{{1, 0.239031, {2.32481, 1.50199, 1.96469, 1.98323, 3.95088}},  0.813374}, {{4,  4.31327, {2.54655, 1.79435, 0.872495, 4.23126,  1.26728}}, -0.871972}, {{3,  4.76864, {3.99304, 4.44505, 1.01705, 0.960288,  0.110293}}, -1.99016}, {{1,  2.04859, {3.90707, 1.08609, 1.52017, 2.15679,  4.95573}}, -0.959189}, {{3,  0.847063, {4.19536, 0.654802, 2.99104, 3.86383, 0.244481}},  2.87215}, {{4,  1.34154, {0.444491, 2.06948, 4.37199, 2.11028, 4.17721}},  2.91859}, {{2,  2.30083, {0.378949, 2.66522, 3.16016, 1.34055,  0.268656}}, -2.06784}, {{5,  0.616637, {4.2531, 0.254452, 3.74849, 3.45984, 4.29736}},  4.89926}, {{0,  4.40739, {4.55313, 2.80504, 1.30632, 0.543558,  4.30865}}, -4.50771}, {{0,  1.4635, {0.861832, 3.47408, 4.93666, 4.35323,  1.68462}}, -0.760289}};

  for (unsigned int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
    {
#define taufunc(_k) data[i].input.tau[_k]
      double actual = dlog_polytomous_rasch_dbeta (data[i].input.x,
                                                   data[i].input.beta,
                                                   taufunc,
                                                   5);
#undef taufunc

      assert (      fabs (actual - data[i].output) 
                 <= 1e-5 * (1 + fabs (actual) + fabs (data[i].output))
              || (fprintf (stderr, "fail: %g != %g\n", actual, data[i].output),
                  0));
    }
}

typedef struct _PolytomousRaschDTauTestDatum PolytomousRaschDTauTestDatum;
struct _PolytomousRaschDTauTestDatum 
{
  struct
    {
      unsigned int  x;
      double        beta;
      double        tau[5];
    }                           input;

  double                        output[5];
};

static void
test_dtau (void)
{
  PolytomousRaschDTauTestDatum data[] = 
    {{{4, 1.07137, {4.27136, 4.57825, 0.540569, 2.61152,  4.97399}}, {-0.957379, -0.996404, -0.997575, -0.999565,  8.61155e-6}}, {{5,  0.170863, {0.987442, 4.80648, 3.66767, 4.6273,  1.6788}}, {-0.691391, -0.996945, -0.999909, -0.999999, -1.}}, {{0,  3.34298, {2.80584, 1.15322, 1.74213, 3.98975,  1.12122}}, {0.997998, 0.994572, 0.96397, 0.812269,  0.732819}}, {{3,  4.97997, {2.18442, 2.30174, 2.59676, 0.14727,  2.89537}}, {-3.40625e-7, -5.91723e-6, -0.000087109,  0.999033, 0.888537}}, {{3,  1.23038, {3.3254, 0.569018, 2.3548, 3.61885,  3.35141}}, {-0.691126, -0.776181, -0.940969, 0.00550142,  0.000589032}}, {{5,  0.398155, {1.36735, 3.81237, 4.68374, 0.770851,  4.68856}}, {-0.718307, -0.990824, -0.99979, -0.999914, -0.999999}}, {{3,  0.469389, {1.8779, 4.61763, 2.94642, 1.47964,  0.756685}}, {-0.800705, -0.996483, -0.999575, 0.000165504,  0.0000709461}}, {{3,  4.63766, {0.762002, 4.1779, 3.15993, 4.49039,  2.86664}}, {-0.000319812, -0.0157393, -0.0401589, 0.852811,  0.728798}}, {{4,  2.94752, {4.83452, 3.92137, 0.511841, 4.32867,  1.48311}}, {-0.365353, -0.420714, -0.441619, -0.680436,  0.259552}}, {{0,  3.52321, {4.14449, 0.516301, 1.79938, 2.75236,  4.45593}}, {0.996106, 0.994014, 0.951701, 0.714497, 0.201755}}};

  for (unsigned int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
    {
      double actual[5];
#define taufunc(_k) data[i].input.tau[_k]
      dlog_polytomous_rasch_dtau (actual,
                                  data[i].input.x,
                                  data[i].input.beta,
                                  taufunc,
                                  5);
#undef taufunc

      for (unsigned int j = 0; j < 5; ++j)
        {
          assert (      fabs (actual[j] - data[i].output[j]) 
                     <= 1e-5 * (1 + fabs (actual[j]) + fabs (data[i].output[j]))
                  || (fprintf (stderr, "fail: %g != %g\n", actual[j], data[i].output[j]),
                      0));
        }
    }
}

int 
main (void)
{
  test_polytomous_rasch ();
  test_dbeta ();
  test_dtau ();

  return 0;
}
